package com.sure.minion.services.base.dao;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.util.Assert;

import com.sure.minion.services.base.handler.exception.DBAutoHandledException;
import com.sure.minion.services.base.handler.exception.DefaultAutoHandledException;
import com.sure.minion.services.base.utils.BaseUtil;
import com.sure.minion.services.base.vo.BaseQuery;
import com.sure.minion.services.base.vo.PagedResult;
import com.sure.minion.services.base.vo.QueryAssist;


/**
 * @Description 基础封装DAO
 * @author syuan
 * @date 2015年8月28日  下午1:42:14
 * Company: TravelSky
 */
@Repository
public class BaseDao implements IBaseDao {
	private static Logger logger = LoggerFactory.getLogger(BaseDao.class);
	@PersistenceContext
	private EntityManager entityManager;
	@Resource
	private JdbcTemplate jdbcTemplate;
	/**
	 * 根据传入的对象进行批量更新操作
	 * @param updateSql	要更新的sql语句
	 * @param fields	传入的？对应对性中的姓名
	 * @param objectList	要更新的对象数组
	 * @param batchNumber	分批量执行数，比如500条提交一次
	 * @return 返回操作是否成功
	 */
	public <T> Boolean  batchUpdate (String updateSql,String[] fields,List<T> objectList,int batchNumber){
		//查询所使用到的列
		List<String> queryFields = Arrays.asList(fields); 
		List<Object[]> argsList = new ArrayList<Object[]>();
		Boolean batchState = true;
		for(int j=1;j<objectList.size()+1;j++){
			Object object = objectList.get(j-1);
			Object[] obj=  new Object[queryFields.size()];
			// 拿到该类  
	        Class<?> clz = object.getClass(); 
	        // 获取实体类的所有属性，返回Field数组  
	        Field[] objectFields = clz.getDeclaredFields();
	        for (Field field : objectFields) {
	        	//传入数组
	        	for(int i=0;i<queryFields.size();i++){
	        		if(queryFields.get(i).equals(field.getName())){
	        			Method m;
							try {
								m = (Method) object.getClass().getMethod(  
								        "get" + getMethodName(field.getName()));
								obj[queryFields.indexOf(queryFields.get(i))] = m.invoke(object);
							} catch (Exception e) {
								throw new DefaultAutoHandledException(e);
							}
	        		}
	        	}
	        }
	        if(obj!=null){
	        	argsList.add(obj);
	        }
	        if(j%batchNumber==0){
	        	int [] retVal = jdbcTemplate.batchUpdate(updateSql, argsList);
	        	logger.info("当前批量对象为"+clz.getSimpleName()+"-----当前批量总数为-------"+objectList.size()+"------条，当前已经执行了-------"+j+"--------条！");
	        	argsList.clear();
	        	for(int x=0;x<retVal.length;x++){
	        		if (retVal[x]!=-2) {
	        			batchState=false;
					}
	        	}
	        }else if(j==objectList.size()){
	        	int [] retVal = jdbcTemplate.batchUpdate(updateSql, argsList);
	        	logger.info("当前批量对象为"+clz.getSimpleName()+"当前批量总数为-------"+objectList.size()+"------条，当前已经执行了-------"+j+"--------条！");
	        	argsList.clear();
	        	for(int x=0;x<retVal.length;x++){
	        		if (retVal[x]!=-2) {
	        			batchState=false;
					}
	        	}
	        }
		}
		return batchState;          
	}
	// 把一个字符串的第一个字母大写、效率是最高的、  
    private static String getMethodName(String fildeName) throws Exception{  
        byte[] items = fildeName.getBytes();  
        items[0] = (byte) ((char) items[0] - 'a' + 'A');  
        return new String(items);  
    } 
	
	@Override
	public void save(Object obj) {
		try {
			entityManager.persist(obj);
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_SAVE_ERROR", e, "By JPA");
		}
	}

	@Override
	public void update(Object obj) {
		try {
			entityManager.merge(obj);
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_UPDATE_ERROR", e, "By JPA");
		}
	}

	@Override
	public int updateBySql(final String sql) {
		try {
			return entityManager.createNativeQuery(sql).executeUpdate();
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_UPDATE_ERROR", e, "By SQL");
		}
	}

	/**
	 * 按字段更新
	 * 
	 * @Description
	 * @param updateFieldPropertyMap
	 *            需要更新的字段
	 * @param criteriapPropertyMap
	 *            条件字段
	 * @param clazz
	 * @author wangxs
	 * @date 2015年2月9日 下午2:41:54
	 */
	public void updateDataByField(
			SortedMap<String, Object> updateFieldPropertyMap,
			SortedMap<String, Object> criteriapPropertyMap, Class<?> clazz) {

		// 声明是否执行更新操作的标志变量
		boolean updateflag = false;
		// 声明需要更新字段值的集合变量
		final List<Object> valueList = new ArrayList<Object>();

		// 声明SQL语句变量
		StringBuffer sqlBuffer = new StringBuffer("UPDATE ");
		sqlBuffer.append(clazz.getName()).append(" SET ");
		String propeytValue = null;

		// 构造SQL语句,更新时忽略对主键的更新
		for (Map.Entry<String, Object> entry : updateFieldPropertyMap
				.entrySet()) {
			propeytValue = entry.getKey();
			if (BaseUtil.stringNotNull(propeytValue)) {
				if (updateflag) {
					sqlBuffer.append(",").append(propeytValue).append("=?");
				} else {
					updateflag = true;
					sqlBuffer.append(propeytValue).append("=?");
				}
				valueList.add(entry.getValue());
			}
		}

		// 判断是否需要执行更新操作
		if (!updateflag) {
			return;
		} else {
			sqlBuffer.append(" where ");
			updateflag = false;
		}

		for (Map.Entry<String, Object> entry : criteriapPropertyMap.entrySet()) {
			propeytValue = entry.getKey();
			if (BaseUtil.stringNotNull(propeytValue)) {
				if (updateflag) {
					sqlBuffer.append(" and ").append(propeytValue).append("=?");
				} else {
					updateflag = true;
					sqlBuffer.append(propeytValue).append("=?");
				}
				valueList.add(entry.getValue());
			}
		}

		// 防止忘了设置条件的更新语句
		if (!updateflag) {
			return;
		}
		// 防止除了agentid，没有设置其他条件
		if(criteriapPropertyMap.size() ==1 && criteriapPropertyMap.containsKey("agnetId")){
			return;
		}

		final String sqlStr = sqlBuffer.toString();
		this.updateByJpql(sqlStr, valueList.toArray());
	}

	/**
	 * 按字段删除
	 * 
	 * @Description
	 * @param updateFieldPropertyMap
	 *            需要更新的字段
	 * @param criteriapPropertyMap
	 *            条件字段
	 * @param clazz
	 * @author wangxs
	 * @date 2015年2月9日 下午2:41:54
	 */
	public void deleteDataByField(
			SortedMap<String, Object> criteriapPropertyMap, Class<?> clazz) {

		// 声明是否执行更新操作的标志变量
		boolean updateflag = false;
		// 声明需要更新字段值的集合变量
		final List<Object> valueList = new ArrayList<Object>();

		// 声明SQL语句变量
		StringBuffer sqlBuffer = new StringBuffer("DELETE ");
		sqlBuffer.append(" FROM ").append(clazz.getSimpleName())
				.append(" where ");

		String propeytValue = null;

		for (Map.Entry<String, Object> entry : criteriapPropertyMap.entrySet()) {
			propeytValue = entry.getKey();
			if (propeytValue != null && propeytValue != "") {
				if (updateflag) {
					sqlBuffer.append(" and ").append(propeytValue).append("=?");
				} else {
					updateflag = true;
					sqlBuffer.append(propeytValue).append("=?");
				}
				valueList.add(entry.getValue());
			}
		}

		// 防止忘了设置条件的删除语句
		if (!updateflag) {
			return;
		}
		
		// 防止除了agentid，没有设置其他条件
		if(criteriapPropertyMap.size() ==1 && criteriapPropertyMap.containsKey("agnetId")){
			return;
		}

		final String sqlStr = sqlBuffer.toString();
		this.updateByJpql(sqlStr, valueList.toArray());
	}

	public int updateByJpql(final String sql, final Object... values) {
		Query query = entityManager.createQuery(sql);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i + 1, values[i]);
		}
		try {
			return query.executeUpdate();
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_QUERY_ERROR", e, "By JPQL");
		}
	}

	@Override
	public int updateBySql(final String sql, final Object... values) {
		Query query = entityManager.createNativeQuery(sql);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i + 1, values[i]);
		}
		try {
			return query.executeUpdate();
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_UPDATE_ERROR", e, "By SQL");
		}
	}

	@Override
	public void delete(Object obj) {
		try {
			entityManager.remove(obj);
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_DELETE_ERROR", e, "By JPA");
		}
	}

	@Override
	public <T> void delete(Class<T> entityClass, Serializable id) {
		T obj = entityManager.find(entityClass, id);
		if (obj != null) {
			try {
				entityManager.remove(obj);
			} catch (Exception e) {
				throw new DBAutoHandledException("COMMON_DB_DELETE_ERROR", e, "By JPA");
			}
		}
	}

	@Override
	public <T> T queryById(Class<T> entityClass, Serializable id) {
		try {
			return (T) entityManager.find(entityClass, id);
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_QUERY_ERROR", e, "BY JPA");
		}
	}

	@Override
	@SuppressWarnings("rawtypes")
	public List queryByJPQL(String jpql) {
		try {
			return entityManager.createQuery(jpql).getResultList();
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_QUERY_ERROR", e, "By JPQL");
		}

	}

	@Override
	@SuppressWarnings("rawtypes")
	public List queryBySQL(final String sql) {
		try {
			return entityManager.createNativeQuery(sql).getResultList();
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_QUERY_ERROR", e, "By SQL");
		}

	}

	/**
	 * 根据自己拼写的sql查询返回对象数组
	 * 
	 * @param sql
	 *            已经拼写好的sql
	 * @param entityClass
	 *            实体类
	 * @param values
	 *            传入的参数值
	 * @return
	 */
	public <T> List<T> queryBySQLForList(final String sql,
			Class<T> entityClass, final Object... values) {
		try {
			Query query = entityManager.createNativeQuery(sql, entityClass);
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i + 1, values[i]);
			}
			@SuppressWarnings("unchecked")
			List<T> list = query.getResultList();
			return list;
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_QUERY_ERROR", e, "By SQL");
		}

	}

	@Override
	public void execBySQL(final String sql, final Object... values) {
		Query query = entityManager.createNativeQuery(sql);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i + 1, values[i]);
		}
		try {
			query.executeUpdate();
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_EXECUTE_ERROR", e, "By SQL");
		}

	}

	@Override
	@SuppressWarnings("rawtypes")
	public List queryBySQL(final String sql, final Object... values) {
		Query query = entityManager.createNativeQuery(sql);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i + 1, values[i]);
		}
		try {
			return query.getResultList();
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_QUERY_ERROR", e, "By SQL");
		}

	}

	@Override
	@SuppressWarnings("rawtypes")
	public List queryPageBySQL(final String sql, final int rowStartIdx,
			final int rowCount, final Object... values) {
		Query query = entityManager.createNativeQuery(sql);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i + 1, values[i]);
		}
		if (rowStartIdx >= 0) {
			query.setFirstResult(rowStartIdx);
		}
		if (rowCount > 0) {
			query.setMaxResults(rowCount);
		}
		try {
			return query.getResultList();
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_QUERY_PAGE_ERROR", e, "By SQL");
		}

	}

	@Override
	@SuppressWarnings("rawtypes")
	public List queryPageBySQL(final String sql, final int rowStartIdx,
			final int rowCount) {
		Query query = entityManager.createNativeQuery(sql);
		if (rowStartIdx >= 0) {
			query.setFirstResult(rowStartIdx);
		}
		if (rowCount > 0) {
			query.setMaxResults(rowCount);
		}
		try {
			return query.getResultList();
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_QUERY_PAGE_ERROR", e, "By SQL");
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	public <T> List<T> queryAll(final Class<T> entityClass) {
		StringBuffer jpql = new StringBuffer("from ");
		jpql.append(entityClass.getName());
		jpql.append(" obj");
		try {
			return entityManager.createQuery(jpql.toString()).getResultList();
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_QUERY_ERROR", e, "By JPQL");
		}

	}

	@Override
	@SuppressWarnings("rawtypes")
	public <T> int queryRowCount(final Class<T> entityClass) {
		StringBuffer strBuff = new StringBuffer("select count(*) from ");
		strBuff.append(entityClass.getName());
		List list = entityManager.createQuery(strBuff.toString())
				.getResultList();

		Object ob = list.get(0);
		try {
			return Integer.parseInt(String.valueOf(ob));
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_QUERY_COUNT_ERROR", e, "By JPQL");
		}

	}
	
	@Override
	@SuppressWarnings("rawtypes")
	public List queryByJPQL(final String queryString, final Object... values) {
		Query query = entityManager.createQuery(queryString);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i + 1, values[i]);
		}
		try {
			return query.getResultList();
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_QUERY_ERROR", e, "By JPQL");
		}

	}
	
	@Override
	@SuppressWarnings("unchecked")
	public <T> List<T> queryByJPQL(final String queryString,
			Class<T> entityClass, final Object... values) {
		Query query = entityManager.createQuery(queryString, entityClass);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i + 1, values[i]);
		}
		try {
			return (List<T>)query.getResultList();
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_QUERY_ERROR", e, "By JPQL");
		}
		
	}

	@Override
	@SuppressWarnings("rawtypes")
	public List queryPagedByJPQL(final String queryString,
			final int rowStartIdx, final int rowCount, final Object... values) {
		Query query = entityManager.createQuery(queryString);

		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i + 1, values[i]);
			}
		}
		if (rowStartIdx >= 0) {
			query.setFirstResult(rowStartIdx);
		}
		if (rowCount > 0) {
			query.setMaxResults(rowCount);
		}
		try {
			return query.getResultList();
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_QUERY_PAGE_ERROR", e, "By JPQL");
		}

	}

	@Override
	@SuppressWarnings({ "unchecked" })
	public int queryCountByJPQL(final String queryString,
			final Object... values) {
		Query query = entityManager.createQuery(queryString);

		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i + 1, values[i]);
			}
		}
		List<Object> list = null;
		try {
			list = query.getResultList();
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_QUERY_COUNT_ERROR", e, "By JPQL");
		}
		Object ob = list.get(0);
		return Integer.parseInt(String.valueOf(ob));
	}

	@Override
	@SuppressWarnings("unchecked")
	public <T> T queryFirst(Class<T> entityClass, final String queryString,
			final Object... values) {
		Assert.hasLength(queryString);

		Query query = entityManager.createQuery(queryString);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i + 1, values[i]);
		}
		List<T> results = null;
		try {
			results = query.getResultList();
		} catch (Exception e) {
			throw new DBAutoHandledException("COMMON_DB_QUERY_ERROR", e, "By JPQL");
		}
		if (results == null || results.isEmpty()) {
			return null;
		}
		return results.iterator().next();
	}

	@Override
	@SuppressWarnings("unchecked")
	public <T> List<T> queryForResult(BaseQuery baseQuery) {
		QueryAssist queryAssist = baseQuery.buildQueryString(false);
		return queryByJPQL(queryAssist.getQueryString(),
				queryAssist.getQueryParas());
	}

	@Override
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public <T> PagedResult<T> queryForPagedResult(BaseQuery baseQuery) {
		
		if(baseQuery.getNumPerPage()<=0){
			baseQuery.setNumPerPage(10);
		}

		PagedResult<T> pagedResult = new PagedResult<T>();

		// 计算要查询的记录起始数
		int numFrom = (baseQuery.getCurrentPage() - 1) >= 0 ? (baseQuery
				.getCurrentPage() - 1) * baseQuery.getNumPerPage() : 0;

		// 获得查询字符串和参数数组
		QueryAssist queryAssist = baseQuery.buildQueryString(false);
		// 调用分页方式查询
		List<T> resultList = this.queryPagedByJPQL(
				queryAssist.getQueryString(), numFrom,
				baseQuery.getNumPerPage(), queryAssist.getQueryParas());

		pagedResult.setResultList(resultList);

		// 获得查询总数量用的字符串和参数数组
		QueryAssist countQueryAssist = baseQuery.buildQueryString(true);
		// 调用查询
		List list = this.queryByJPQL(countQueryAssist.getQueryString(),
				countQueryAssist.getQueryParas());

		// 获取总数和计算总页数
		Object ob = list.get(0);
		int totalNum = Integer.parseInt(String.valueOf(ob));
		int totalPage = (totalNum % baseQuery.getNumPerPage() == 0) ? totalNum
				/ baseQuery.getNumPerPage() : totalNum
				/ baseQuery.getNumPerPage() + 1;

		// 把当前页、每页数量、总数和总页数放入返回对象
		pagedResult.setCurrentPage(baseQuery.getCurrentPage());
		pagedResult.setNumPerPage(baseQuery.getNumPerPage());
		pagedResult.setTotalNum(totalNum);
		pagedResult.setTotalPage(totalPage);

		return pagedResult;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public <T> PagedResult<T> queryForPagedResultBySql(BaseQuery baseQuery) {

		if(baseQuery.getNumPerPage()<=0){
			baseQuery.setNumPerPage(10);
		}
		
		PagedResult<T> pagedResult = new PagedResult<T>();

		// 计算要查询的记录起始数
		int numFrom = (baseQuery.getCurrentPage() - 1) >= 0 ? (baseQuery
				.getCurrentPage() - 1) * baseQuery.getNumPerPage() : 0;

		// 获得查询字符串和参数数组
		QueryAssist queryAssist = baseQuery.buildQueryString(false);
		// 调用分页方式查询
		List<T> resultList = this
				.queryPageBySQL(queryAssist.getQueryString(), numFrom,
						baseQuery.getNumPerPage(), queryAssist.getQueryParas());

		pagedResult.setResultList(resultList);

		// 获得查询总数量用的字符串和参数数组
		QueryAssist countQueryAssist = baseQuery.buildQueryString(true);
		// 调用查询
		List list = this.queryBySQL(countQueryAssist.getQueryString(),
				countQueryAssist.getQueryParas());

		// 获取总数和计算总页数
		Object ob = list.get(0);
		int totalNum = Integer.parseInt(String.valueOf(ob));
		int totalPage = (totalNum % baseQuery.getNumPerPage() == 0) ? totalNum
				/ baseQuery.getNumPerPage() : totalNum
				/ baseQuery.getNumPerPage() + 1;

		// 把当前页、每页数量、总数和总页数放入返回对象
		pagedResult.setCurrentPage(baseQuery.getCurrentPage());
		pagedResult.setNumPerPage(baseQuery.getNumPerPage());
		pagedResult.setTotalNum(totalNum);
		pagedResult.setTotalPage(totalPage);

		return pagedResult;
	}

	@Override
	public <T> void batchSave(List<T> objList, Integer batchSize) {
		try {
			for (int i = 1; i <= objList.size(); i++) {
				entityManager.persist(objList.get(i-1));
				if (i % batchSize == 0 || i == objList.size()) {
					entityManager.flush();
					entityManager.clear();
					logger.info("当前批量对象为"+objList.get(i-1).getClass().getSimpleName()+"当前批量总数为-------"+objList.size()+"------条，当前已经执行了-------"+i+"--------条！");
				}
			}
		} catch (Exception e) {
			throw new DBAutoHandledException("DB_BATCHSAVE_ERROR", e, "By JPA");
		} finally {
			entityManager.close();
		}
	}

	@Override
	public <T> void batchSaveOrUpdate(List<T> objList, Integer batchSize) {
		try {
			for (int i = 1; i <= objList.size(); i++) {
				entityManager.merge(objList.get(i-1));
				if (i % batchSize == 0 || i == objList.size()) {
					entityManager.flush();
					entityManager.clear();
					logger.info("当前批量对象为"+objList.get(i-1).getClass().getSimpleName()+"当前批量总数为-------"+objList.size()+"------条，当前已经执行了-------"+i+"--------条！");
				}
			}
		} catch (Exception e) {
			throw new DBAutoHandledException("DB_BATCHSAVEORUPDATE_ERROR", e, "By JPA");
		} finally {
			entityManager.close();
		}
	}

	@Override
	public <T> void batchDelete(List<T> objList, Integer batchSize) {
		try {
			for (int i = 1; i <= objList.size(); i++) {
				entityManager.remove(entityManager.merge(objList.get(i-1))); // 为当前session获取游离态数据的删除权限
				if (i % batchSize == 0 || i == objList.size()) {
					entityManager.flush();
					entityManager.clear();
				}
			}
		} catch (Exception e) {
			throw new DBAutoHandledException("DB_BATCHDELETE_ERROR", e,"By JPA");
		} finally {
			entityManager.close();
		}
	}

	public EntityManager getEntityManager() {
		return entityManager;
	}

	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}

}
